package com.yk.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yk.api.system.dto.DeviceDTO;
import com.yk.api.system.dto.LogininforDTO;
import com.yk.api.system.dto.OperLogDTO;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.domain.LoginUser;
import com.yk.common.core.domain.PageResult;
import com.yk.common.core.domain.Result;
import com.yk.common.core.utils.LoginHelper;
import com.yk.common.excel.utils.ExcelUtil;
import com.yk.system.convert.LogininforConvert;
import com.yk.system.convert.OperLogConvert;
import com.yk.system.entity.Logininfor;
import com.yk.system.entity.OperLog;
import com.yk.system.service.DeviceService;
import com.yk.system.service.LogininforService;
import com.yk.system.service.OperLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 日志管理 yk-system
 *
 * @author lmx
 * @date 2023/10/16 18:15
 */
@Api(tags = "日志管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/log")
public class LogController {

    private final LogininforService logininforService;
    private final LogininforConvert logininforConvert;
    private final OperLogService operLogService;
    private final OperLogConvert operLogConvert;
    private final DeviceService deviceService;

    @ApiOperation("新增操作日志记录")
    @PostMapping("/addOperLog")
    public Result<Void> addOperLog(@RequestBody OperLogDTO dto) {
        try {
            if (Objects.isNull(dto)) {
                return Result.fail();
            }
            operLogService.save(operLogConvert.dto2Entity(dto));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.ok();
    }

    @ApiOperation("分页查询操作日志记录")
    @PostMapping("/operLogPage")
    public PageResult<OperLogDTO> operLogPage(@RequestBody BasePageQuery<OperLogDTO> pageParam) {
        OperLogDTO param = pageParam.getParam();
        List<Long> userIds = CollUtil.newArrayList(LoginHelper.getLoginUserId());
        LambdaQueryWrapper<OperLog> lambda = new QueryWrapper<OperLog>().lambda();
        if (NumberConstant.ZERO.equals(param.getType())) {
            // 0其它 1新增 2修改 3删除 4设备上线 5设备下线 7网关转让 8控制下发
            lambda.in(OperLog::getBusinessType, CollUtil.newArrayList(0, 1, 2, 3, 7, 8));
        } else if (NumberConstant.ONE.equals(param.getType())) {
            lambda.in(OperLog::getBusinessType, CollUtil.newArrayList(4, 5));
        }
        if (Objects.nonNull(param.getDeviceId())) {
            lambda.eq(OperLog::getDeviceId, param.getDeviceId());
            userIds.add(1L);
        } else {
            List<DeviceDTO> dtoList = deviceService.selectRole2Device();
            if (CollUtil.isNotEmpty(dtoList)) {
                List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
                ids.add(0L);
                lambda.in(OperLog::getDeviceId, ids);
                userIds.add(1L);
            }
        }
        lambda.in(OperLog::getCreatedBy, userIds);
        lambda.like(StrUtil.isNotBlank(param.getOperName()), OperLog::getOperName, param.getOperName());
        lambda.between(Objects.nonNull(param.getStartTime()), OperLog::getCreatedAt, param.getStartTime(), param.getEndTime());
        lambda.orderByDesc(OperLog::getCreatedAt);
        IPage<OperLogDTO> page = operLogService.page(new Page<>(pageParam.getPageNum(), pageParam.getPageSize()), lambda)
                .convert(operLogConvert::entity2Dto);
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    @ApiOperation("设备上下线日志")
    @PostMapping("/deviceLog")
    public Result<List<OperLogDTO>> deviceLog(@RequestBody OperLogDTO dto) {
        LambdaQueryWrapper<OperLog> lambda = new QueryWrapper<OperLog>().lambda();
        if (Objects.isNull(dto.getDeviceId())) {
            List<DeviceDTO> dtoList = deviceService.selectRole2Device();
            if (CollUtil.isEmpty(dtoList)) {
                return Result.data(CollUtil.newArrayList());
            }
            List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
            lambda.in(OperLog::getDeviceId, ids);
        }
        lambda.eq(Objects.nonNull(dto.getDeviceId()), OperLog::getDeviceId, dto.getDeviceId());
        lambda.in(OperLog::getBusinessType, CollUtil.newArrayList(4, 5));
        lambda.between(Objects.nonNull(dto.getStartTime()), OperLog::getCreatedAt, dto.getStartTime(), dto.getEndTime());
        lambda.orderByDesc(OperLog::getCreatedAt);
        List<OperLog> list = operLogService.list(lambda);
        if (CollUtil.isEmpty(list)) {
            return Result.ok();
        }
        List<OperLogDTO> collect = list.stream().map(operLogConvert::entity2Dto).collect(Collectors.toList());
        return Result.data(collect);
    }

    @ApiOperation("新增系统访问记录")
    @PostMapping("/addLogininfor")
    public Result<Void> addLogininfor(@RequestBody LogininforDTO dto) {
        if (Objects.isNull(dto)) {
            return Result.fail();
        }
        dto.setLoginTime(new Date());
        logininforService.save(logininforConvert.dto2Entity(dto));
        return Result.ok();
    }

    @ApiOperation("分页查询系统访问记录")
    @PostMapping("/LoginLogPage")
    public PageResult<LogininforDTO> LoginLogPage(@RequestBody BasePageQuery<LogininforDTO> pageParam) {
        LambdaQueryWrapper<Logininfor> lambda = new QueryWrapper<Logininfor>().lambda();
        IPage<LogininforDTO> page = logininforService.page(new Page<>(pageParam.getPageNum(), pageParam.getPageSize()), lambda)
                .convert(logininforConvert::entity2Dto);
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    @ApiOperation("导出")
    @GetMapping("/export")
    public void export(OperLogDTO dto, HttpServletResponse response) {
        if (Objects.isNull(dto) || StrUtil.isEmpty(dto.getToken())) {
            return;
        }
        LoginUser loginUser = LoginHelper.getLoginUser(dto.getToken());
        if (Objects.isNull(loginUser)) {
            return;
        }
        LambdaQueryWrapper<OperLog> lambda = new QueryWrapper<OperLog>().lambda();
        if (Objects.isNull(dto.getDeviceId())) {
            List<DeviceDTO> dtoList = deviceService.selectRole2Token(dto.getToken());
            if (CollUtil.isNotEmpty(dtoList)) {
                List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
                ids.add(0L);
                lambda.in(OperLog::getDeviceId, ids);
            }
        }
        ArrayList<Integer> operTypeList = CollUtil.newArrayList(0, 1, 2, 3);
        ArrayList<Integer> onlineTypeList = CollUtil.newArrayList(4, 5);
        if (NumberConstant.ZERO.equals(dto.getType())) {
            lambda.in(OperLog::getBusinessType, operTypeList);
        } else if (NumberConstant.ONE.equals(dto.getType())) {
            lambda.in(OperLog::getBusinessType, onlineTypeList);
        }
        lambda.eq(Objects.nonNull(dto.getDeviceId()), OperLog::getDeviceId, dto.getDeviceId());
        lambda.in(OperLog::getCreatedBy, CollUtil.newArrayList(loginUser.getUserId(), NumberConstant.ONE));
        lambda.like(StrUtil.isNotBlank(dto.getOperName()), OperLog::getOperName, dto.getOperName());
        lambda.between(Objects.nonNull(dto.getStartTime()), OperLog::getCreatedAt, dto.getStartTime(), dto.getEndTime());
        lambda.orderByDesc(OperLog::getCreatedAt);
        List<OperLog> list = operLogService.list(lambda);
        List<OperLogDTO> dtoList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(list)) {
            AtomicInteger index = new AtomicInteger(1);
            list.forEach(it -> {
                OperLogDTO operLogDTO = operLogConvert.entity2Dto(it);
                Integer type = operLogDTO.getBusinessType() == null ? 0 : operLogDTO.getBusinessType();
                operLogDTO.setTypeStr("上下线");
                if (operTypeList.contains(type)) {
                    operLogDTO.setTypeStr("操作");
                }
                operLogDTO.setIndex(index.getAndIncrement());
                dtoList.add(operLogDTO);
            });
        }
        ExcelUtil.exportExcel(dtoList, "数据", "日志", OperLogDTO.class, response);
    }
}
